﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Atlepage.Syntactic
{
    class LRItem : IEquatable<LRItem>
    {
        int dot;
        Production production;
        string cachedString;

        public int Dot { get { return dot; } }
        public Production Production { get { return production; } }

        public LRItem(int dot, Production production)
        {
            this.dot = dot;
            this.production = production;
        }

        public static IEnumerable<LRItem> CreateItems(Production production)
        {
            return from x in Enumerable.Range(0, production.Nodes.Length + 1)
                   select new LRItem(x, production);
        }

        public ProductionNode Current
        {
            get
            {
                if (dot == production.Nodes.Length)
                    return null;
                return production.Nodes[dot];
            }
        }

        public ProductionNode Previous
        {
            get
            {
                int prev = dot - 1;
                if (prev < 0)
                    return null;
                return production.Nodes[prev];
            }
        }

        public bool StartsTheSame(LRItem item)
        {
            if (item.production.Nodes.Length < dot)
                return false;
            for (int i = 0; i < dot; i++)
            {
                if (production.Nodes[i] != item.production.Nodes[i])
                    return false;
            }
            return true;
        }

        public override string ToString()
        {
            if (cachedString == null)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(production.Name);
                sb.Append(" :");
                int i;
                for (i = 0; i < production.Nodes.Length; i++)
                {
                    if (i == dot)
                        sb.Append(" .");
                    sb.Append(" ");
                    sb.Append(production.Nodes[i]);
                }
                if (i == dot)
                    sb.Append(" .");
                cachedString = sb.ToString();
            }
            return cachedString;
        }

        public override int GetHashCode()
        {
            return dot.GetHashCode() + production.GetHashCode();
        }

        #region IEquatable<LRItem> Members

        public bool Equals(LRItem other)
        {
            return dot == other.dot && production == other.production;
        }

        public override bool Equals(object obj)
        {
            return Equals((LRItem)obj);
        }

        #endregion

    }
}
